package cn.tedu.blog.server.service.impl;

import cn.tedu.blog.server.controller.system.UploadController;
import cn.tedu.blog.server.exception.ServiceException;
import cn.tedu.blog.server.mapper.RoleMapper;
import cn.tedu.blog.server.mapper.UserMapper;
import cn.tedu.blog.server.pojo.dto.UserAddNewDTO;
import cn.tedu.blog.server.pojo.dto.UserLoginDTO;
import cn.tedu.blog.server.pojo.entity.User;
import cn.tedu.blog.server.pojo.vo.UserListVO;
import cn.tedu.blog.server.security.UserDetails;
import cn.tedu.blog.server.service.IUserService;
import cn.tedu.blog.server.utils.JwtUtils;
import cn.tedu.blog.server.utils.ServiceCode;
import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author: 雷茂林
 * @Date:2022/7/15 14:50
 * @Description: 用户管理-业务逻辑实现类
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;



    @Override
    public void createUser(UserAddNewDTO userAddNewDTO) {
        log.debug("准备开始处理创建用户的业务，参数：{}", userAddNewDTO);
        if (userAddNewDTO != null && userAddNewDTO.getUsername().trim().length()<=0 && userAddNewDTO.getPassword().trim().length()<=0 && userAddNewDTO.getNick().trim().length()<=0){
            throw new ServiceException(ServiceCode.ERR_INSERT, "创建用户失败，用户信息为空！");
        }

        if (userMapper.isByUsername(userAddNewDTO.getUsername()) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "该账号【"+userAddNewDTO.getUsername()+"】已被注册");
        }
        if (userMapper.isByNick(userAddNewDTO.getNick()) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "该昵称【"+userAddNewDTO.getNick()+"】已被注册");
        }
        User user = new User();
        BeanUtils.copyProperties(userAddNewDTO,user);
        // 补全代码
        LocalDateTime now = LocalDateTime.now();
        user.setCreatedTime(now);
        user.setGmtModified(now);
        log.debug("即将开始加密...");
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        // 设置默认头像
        if (user.getAvatar()==null || user.getAvatar().trim().length()==0){
            user.setAvatar("https://dome1as32465.oss-cn-chengdu.aliyuncs.com/2022-08-09/a996840f-d993-45dd-920e-cdfd9e76e1e9.jpg");
        }

        log.debug("即将向数据库中写入：{}", user);
        if (userMapper.createUser(user) < 1) {
            throw new ServiceException(ServiceCode.ERR_INSERT, "创建用户失败，请稍后再做尝试");
        }

        // 更新用户角色
        createRoleByUserId(userAddNewDTO);
    }



    @Override
    public void deleteById(Long userId) {
        log.debug("准备开始处理删除用户的业务，参数：{}", userId);
        if (userMapper.isById(userId) < 1) {
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, "该用户不存在");
        }
        String avatar = userMapper.getBackFillById(userId).getAvatar();
        System.out.println(avatar);
        if (userMapper.deleteById(userId) < 1) {
            throw new ServiceException(ServiceCode.ERR_DELETE, "删除失败，请稍后再试");
        }
        roleMapper.clearUserRoleById(userId,null);
        new UploadController().remove1("https://dome1as32465.oss-cn-chengdu.aliyuncs.com/2022-08-09/a996840f-d993-45dd-920e-cdfd9e76e1e9.jpg");
    }



    @Override
    public void deleteByIds(List<Long> list) {
        log.debug("准备开始处批量删除用户的业务，参数：{}", list);
        if (list.size() <= 0) {
            throw new ServiceException(ServiceCode.ERR_DELETE, "没有指定需要删除的用户列表");
        }
        Map<Long,String> avatarsMap = new HashMap<>();
        for (Long aLong : list) {
            avatarsMap.put(aLong,userMapper.getBackFillById(aLong).getAvatar());
        }
        if (userMapper.deleteByIds(list) <= 0) {
            throw new ServiceException(ServiceCode.ERR_DELETE, "批量删除失败，请稍后再试");
        }

        // 删除用户绑定的角色和删除oss中存储的用户头像
        UploadController uploadController = new UploadController();
        Set<Map.Entry<Long,String>> entrySet = avatarsMap.entrySet();
        for (Map.Entry<Long, String> avatars : entrySet) {
            roleMapper.clearUserRoleById(avatars.getKey(),null);
            uploadController.remove(avatars.getValue());
        }
    }



    @Override
    public void updateById(UserAddNewDTO userAddNewDTO) {
        log.debug("准备开始处理【修改用户信息】的业务，参数：{}", userAddNewDTO);
        if (userAddNewDTO.getUsername()!=null){
            if (userMapper.isUpdateByUsername(userAddNewDTO.getId(),userAddNewDTO.getUsername()) > 0) {
                throw new ServiceException(ServiceCode.ERR_CONFLICT, "该账号【"+userAddNewDTO.getUsername()+"】已被使用！");
            }
        }
        if (userAddNewDTO.getNick()!=null){
            if (userMapper.isUpdateByNick(userAddNewDTO.getId(),userAddNewDTO.getNick()) > 0) {
                throw new ServiceException(ServiceCode.ERR_CONFLICT, "该昵称【"+userAddNewDTO.getNick()+"】已被使用！");
            }
        }
        // 设置默认头像
        if (userAddNewDTO.getAvatar()==null || userAddNewDTO.getAvatar().trim().length()==0){
            userAddNewDTO.setAvatar("https://dome1as32465.oss-cn-chengdu.aliyuncs.com/2022-08-09/a996840f-d993-45dd-920e-cdfd9e76e1e9.jpg");
        }
        if (userMapper.updateById(userAddNewDTO) <= 0) {
            throw new ServiceException(ServiceCode.ERR_UPDATE, "修改用户信息失败,请稍后重试！");
        }

        // 更新用户角色
        createRoleByUserId(userAddNewDTO);
    }



    @Override
    public void updateByIdPassword(UserAddNewDTO userAddNewDTO) {
        log.debug("准备开始处理【修改用户密码】的业务，参数：{}", userAddNewDTO);
        if (userMapper.updateByIdPassword(userAddNewDTO) <= 0) {
            throw new ServiceException(ServiceCode.ERR_UPDATE, "修改用户信息失败,请稍后重试！");
        }
    }



    @Override
    public int getCountAll(UserListVO userListVO) {
        log.debug("准备开始处理【条件查询结果集数量】的业务，参数：{}", userListVO);
        return userMapper.getCountAll(userListVO);
    }



    @Override
    public UserListVO getBackFillById(Long id) {
        log.debug("准备开始处理【信息回显】的业务，参数：{}", id);

        return userMapper.getBackFillById(id);
    }



    @Override
    public List<UserListVO> listByKeyword(UserListVO userListVO) {
        log.debug("准备开始【处理条件分页查询】的业务，参数：{}", userListVO);
        return userMapper.listByKeyword(userListVO);
    }



    @Override
    public String login(UserLoginDTO userLoginDTO) {
        log.debug("开始处理【用户登录】的业务，参数：{}", userLoginDTO);
        //调用AuthenticationManager执行Spring Security的认证
        Authentication authentication = new UsernamePasswordAuthenticationToken(userLoginDTO.getUsername(), userLoginDTO.getPassword());
        Authentication loginResult = authenticationManager.authenticate(authentication);

        //以上调用的authenticate方法是会抛出异常的方法，如果还能执行到此处，则表示用户名和密码正确
        //应该在此处生成JWT数据，并将用户登录信息存入JWT
        log.debug("登录成功！认证方法返回：{}>>>{}", loginResult.getClass().getName(), loginResult);

        //从认证结果中获取Principal本质上是User类型，且是UserDe且是UserDetailsService中loadUserByUsername方法返回的结果
        log.debug("尝试获取Principal：{}>>>{}", loginResult.getPrincipal().getClass().getName(), loginResult.getPrincipal());

        UserDetails userDetails = (UserDetails) loginResult.getPrincipal();
        log.debug("登录成功的用户ID：{}", userDetails.getId());
        log.debug("登录成功的用户名：{}", userDetails.getUsername());
        log.debug("登录成功的权限的数据类型：{}", userDetails.getAuthorities().getClass().getName());
        log.debug("登录成功的权限：{}", userDetails.getAuthorities());

        log.debug("将权限转换成JSON：{}", JSON.toJSONString(userDetails.getAuthorities()));

        //提前准备存入令牌的属性值，用户ID，用户名，用户权限
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", userDetails.getId());
        claims.put("username", userDetails.getUsername());
        claims.put("authorities", JSON.toJSONString(userDetails.getAuthorities()));

        String jwt = JwtUtils.generate(claims);
        log.debug("登录成功生成的令牌：{}", jwt);

        UserAddNewDTO userAddNewDTO = new UserAddNewDTO();

        userAddNewDTO.setLastLogin(LocalDateTime.now());
        userAddNewDTO.setId(userDetails.getId());
        userMapper.updateById(userAddNewDTO);
        return jwt;
    }



    /**
     * 更新用户角色
     * @param userAddNewDTO
     */
    private void createRoleByUserId(UserAddNewDTO userAddNewDTO){
        roleMapper.clearUserRoleById(userAddNewDTO.getId(),null);   // 清空用户角色
        Long[] roleIdArray = null;      // 创建角色权限数据

        log.debug("即将更新用户角色");


        if (userAddNewDTO.getOptionsSelect().size()<=0){
            roleIdArray = new Long[1];
            log.debug("默认给当前用户赋予【游客】角色");
            roleIdArray[0] = roleMapper.getRoleIdByRoleName("游客");
        }else {
            roleIdArray = new Long[userAddNewDTO.getOptionsSelect().size()];
            for (int i = 0; i < userAddNewDTO.getOptionsSelect().size(); i++) {
                roleIdArray[i] = userAddNewDTO.getOptionsSelect().get(i)[0];
            }
        }

        int addUserRole = roleMapper.createRoleByUserId(
                userAddNewDTO.getId(),
                roleIdArray,
                userAddNewDTO.getCreatedTime(),
                userAddNewDTO.getGmtModified()
        );
        if (addUserRole<=0){
            throw new ServiceException(ServiceCode.ERR_INSERT, "操作失败，请稍后再做尝试！");
        }
    }

}
